package adnroid.asynchronous.demo;

import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.util.Log;
import android.view.View;
import android.widget.Button;

/**
 * 我们看到，为一个线程建立消息循环有四个步骤：
 * 1、  初始化Looper
 * 2、  绑定handler到CustomThread实例的Looper对象
 * 3、  定义处理消息的方法
 * 4、  启动消息循环
 */

public class Demo03ThreadLooperAndMessageQueueActivity extends Activity {
	
	private Button btnSubmit = null;
	private Handler handler = null;
	private final int MSG_HELLO = 0;  
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		this.setContentView(R.layout.demo03_thread_looper_and_messagequeue);
		
		//新建并启动CustomThread实例 
		 new CustomThread().start();
		 
		btnSubmit = (Button)this.findViewById(R.id.btnSubmit);

		btnSubmit.setOnClickListener(new View.OnClickListener() {
			
			public void onClick(View v) {
				String str = "hello";  
                Log.d("Test", "MainThread is ready to send msg:" + str); 
                
                 //发送消息到CustomThread实例 
                handler.obtainMessage(MSG_HELLO, str).sendToTarget();
				
			}
		});
	}
	
	class CustomThread extends Thread {

		@Override
		public void run() {
			/**
			 * 静态方法prepare()做2件事情： sThreadLocal.set(new Looper()).
			 * 1. 新建一个Looper对象
			 * 		a. 初始化MessageQueue（final变量）
			 * 		b. 记录创建Looper对象的线程ID.
			 * 2. 并放入到线程的局部变量中，而这个变量是不和其他线程共享的。
			 * 		
			 */
			Looper.prepare();
			
			/**
			 * Handler 构造函数中使用looper.myLooper（）静态方法获得刚才创建的Looper对象。
			 * 获得looper对象之后通过looper.Queue属性获得刚才创建的MessageQueue对象(获取消息队列)。
			 * 这样 looper就与handler绑定到了一起。
			 */
			handler = new Handler() {
				public void handleMessage(Message msg) {
					 switch(msg.what) {  
	                    case MSG_HELLO:  
	                        Log.d("Test", "CustomThread receive msg:" + (String) msg.obj);
				
					 }
				}
			};
			
			/**
			 * Looper.loop（）静态方法首先获得Looper对象和MessageQueue对象
			 * 然后queue.Next()方法从消息队列中获取Message对象。
			 * 
			 * msg.target 就是处理这个message的Handler。
			 * 调用handler.obtainMessage(MSG_HELLO, str).sendToTarget() 实际上将handler作为message的一部分发送到了MessageQueue。
			 * 我们在looper方法中的msg.target来指定了由那个Handler来处理当前的Message。
			 * 最后调用msg.target.dispatchMessage(msg)来调用被我们复写的handlerMessage方法()；
			 * -------------------------------------------------------------------------------
			 * 	我們直接由此來作解釋，
				追蹤當中的 obtainMssage 可發現 target的由來。原理如下
				Handler.java: Message obtainMessage(int what, int arg1, int arg2)
				Message.java:
				static Message obtain(Handler h, int what, int arg1, int arg2) {
				        Message m = obtain();
				        m.target = h;  // 這邊就是 msg.target 的由來
				        m.what = what;
				        m.arg1 = arg1;
				        m.arg2 = arg2;
				}
				
				而 Message m = obtain() 是執行下面這段程式
				
				    public static Message obtain() {
				        synchronized (mPoolSync) { //與 recycle() 共用 mPoolSync
				            if (mPool != null) {
				                Message m = mPool;
				                mPool = m.next;
				                m.next = null;
				                return m;
				            }
				        }
				        return new Message();
				    }
				
				因此你可從 sample code 知道
				
			 * （Handler 呼叫 obtainMessage 的時候，其實是由 mPool 取出 Message來將 msg.target 設為原 Handler. 並且設定好 what, arg1, arg2 等參數好讓 Looper 來執行它）
			 */
			Looper.loop();
		}
		
	}
}

/*
------------------------------------------------
源代码： Looper.java
------------------------------------------------

final MessageQueue mQueue;  
private Looper() {  
     mQueue = new MessageQueue();  
     mRun = true;  
     mThread = Thread.currentThread();  
}  

private static final ThreadLocal sThreadLocal = new ThreadLocal();  
public static final void prepare() {  
        if (sThreadLocal.get() != null) {  
            throw new RuntimeException("Only one Looper may be created per thread");  
        }  
        sThreadLocal.set(new Looper());  
}  

public static final void loop() {  
       Looper me = myLooper();  
       MessageQueue queue = me.mQueue;  
         
       // Make sure the identity of this thread is that of the local process,  
       // and keep track of what that identity token actually is.  
       Binder.clearCallingIdentity();  
       final long ident = Binder.clearCallingIdentity();  
         
       while (true) {  
           Message msg = queue.next(); // 可能会阻塞
           //if (!me.mRun) {  
           //    break;  
           //}  
           if (msg != null) {  
               if (msg.target == null) {  
                   // No target is a magic identifier for the quit message.  
                   return;  
               }  
               if (me.mLogging!= null) me.mLogging.println(  
                       ">>>>> Dispatching to " + msg.target + " "  
                       + msg.callback + ": " + msg.what  
                       );  
               msg.target.dispatchMessage(msg);  
               if (me.mLogging!= null) me.mLogging.println(  
                       "<<<<< Finished to    " + msg.target + " "  
                       + msg.callback);  
                 
               // Make sure that during the course of dispatching the  
               // identity of the thread wasn't corrupted.  
               final long newIdent = Binder.clearCallingIdentity();  
               if (ident != newIdent) {  
                   Log.wtf("Looper", "Thread identity changed from 0x"  
                           + Long.toHexString(ident) + " to 0x"  
                           + Long.toHexString(newIdent) + " while dispatching to "  
                           + msg.target.getClass().getName() + " "  
                           + msg.callback + " what=" + msg.what);  
               }  
                 
               msg.recycle();  
           }  
       }  
   }  
------------------------------------------------
源代码：Handler.java
------------------------------------------------
final MessageQueue mQueue;  
final Looper mLooper;  
public Handler() {  
        if (FIND_POTENTIAL_LEAKS) {  
            final Class<? extends Handler> klass = getClass();  
            if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&  
                    (klass.getModifiers() & Modifier.STATIC) == 0) {  
                Log.w(TAG, "The following Handler class should be static or leaks might occur: " +  
                    klass.getCanonicalName());  
            }  
        }  
  
        mLooper = Looper.myLooper();  
        if (mLooper == null) {  
            throw new RuntimeException(  
                "Can't create handler inside thread that has not called Looper.prepare()");  
        }  
        mQueue = mLooper.mQueue;  
        mCallback = null;  
}  

public void dispatchMessage(Message msg) {  
        if (msg.callback != null) {  
            handleCallback(msg);  
        } else {  
            if (mCallback != null) {  
                if (mCallback.handleMessage(msg)) {  
                    return;  
                }  
            }  
            handleMessage(msg);  
        }  
} 


*/